package com.szms.mobile.util;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import dalvik.system.DexClassLoader;
import dalvik.system.DexFile;

public class ReflectionUtils {

    private static List<String> classNames = new ArrayList<>();

    public static Field getDeclaredField(Class cls,String fieldName){
        if (cls.equals(Object.class)){
            return null;
        }

        try {
            Field f = cls.getDeclaredField(fieldName);
            return f;
        } catch (NoSuchFieldException e) {
            return getDeclaredField(cls.getSuperclass(),fieldName);
        }
    }

    /**
     * 获取所有的类名
     * @param context
     * @param packageName
     * @return
     */
    public static List<String> getClassesInPackage(Context context, String packageName) {

        PackageManager packageManager = context.getPackageManager();

        synchronized (ReflectionUtils.class) {
            if (classNames.size()==0) {
                try {
                    // 获取应用信息
                    ApplicationInfo applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0);

                    // 获取应用 APK 文件的路径
                    String apkPath = applicationInfo.sourceDir;

                    // 通过 DexClassLoader 加载 APK 文件
                    DexClassLoader dexClassLoader = new DexClassLoader(apkPath, context.getCacheDir().getAbsolutePath(), null, context.getClassLoader());

                    // 获取 Dex 文件的路径
                    String dexPath = context.getCacheDir() + "/output.dex";

                    // 将 APK 文件解压到 Dex 文件
                    DexFile dexFile = DexFile.loadDex(apkPath, dexPath, 0);

                    // 获取 Dex 文件中的所有类名
                    Enumeration<String> entries = dexFile.entries();
                    while (entries.hasMoreElements()) {
                        String className = entries.nextElement();
                        classNames.add(className);
                    }
                    // 清除 DexClassLoader 缓存
                    //上述代码在获取完类名后，将 DexClassLoader 设置为 null 并触发垃圾回收，以清除类加载器的缓存。这可能有助于解决新增类无法扫描到的问题
                    dexClassLoader = null;
                    System.gc();

                } catch (PackageManager.NameNotFoundException | IOException e) {
                    e.printStackTrace();
                }
            }
        }

        List<String> needClassNames=new ArrayList<>();
        for(String name:classNames){
            if(name.startsWith(packageName)){
                needClassNames.add(name);
            }
        }

        return needClassNames;
    }

    /**
     * 获取所有子类
     * @param context
     * @param packageName
     * @param cls
     * @return
     * @param <T>
     */
    public static <T> List<Class<? extends T>> getSubClassOf(Context context,String packageName,Class<T> cls){
        List<String> classes = getClassesInPackage(context,packageName);
        List<Class<? extends T>> list = new ArrayList<>();
        for (String aClass : classes) {
            Class<?> c = null;
            try {
                c = Class.forName(aClass);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
            if (cls.isAssignableFrom(c)){
                list.add((Class<? extends T>)c);
            }
        }
        return list;
    }
}
